package ru.vsu.amm.io;

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Scanner;

import ru.vsu.amm.algebra.Matrix;

/**
 * 
 * @author Иванов Илья
 * @since 03 января 2013
 *
 */
public class MatrixIO {
	
	/**
	 * Считывает матрицу из текстового файла. Кодировка - UTF-8.
	 * Количество столбцов определяется количеством элементов в первой "числовой" строке.
	 * Количество строк соответствует количеству "числовых" строк в файле корректной размерности.
	 * Если при чтении следующей "числовой" строки в ней оказывается меньше элементов, чем требуется, чтение прекращается.
	 * ЗАМЕЧАНИЕ: строка является "числовой", если она содержит хотя бы один числовой токен.
	 * @param fileName Файл для чтения.
	 * @return Считанная матрица.
	 * @throws IOException При возникновении ошибок ввода-вывода.
	 */
	public static Matrix readFromFile(String fileName) throws IOException {
		List<String> lines = Files.readAllLines(FileSystems.getDefault().getPath(fileName), StandardCharsets.UTF_8);
		if (lines == null)
			throw new IOException("Cannot read matrix lines from file");
		
		int columns = 0;
		List<List<Double>> rows = new ArrayList<>();
		for (String line : lines){
			Scanner sc = new Scanner(line);
			sc.useLocale(Locale.US);
			List<Double> row = new ArrayList<>();
			while ((columns == 0 || row.size() < columns) && sc.hasNext()) {
				if (!sc.hasNextDouble()) {
					sc.next();
					continue;
				}
				
				row.add(sc.nextDouble());
			}
			sc.close();
			if (row.isEmpty())
				continue;
			
			if (columns == 0)
				columns = row.size();
			else if (row.size() < columns)
				break;
			
			rows.add(row);
		}
		
		Matrix A = new Matrix(rows.size(), columns);
		for (int i = 0; i < A.rows(); i++)
			for (int j = 0; j < A.columns(); j++)
				A.set(rows.get(i).get(j), i, j);
		
		return A;
	}
	
	/**
	 * Записывает матрицу в текстовый файл. Кодировка - UTF-8.
	 * @param A Матрица.
	 * @param fileName Имя файла.
	 * @throws IOException Если произошла ошибка ввода-вывода.
	 */
	public static void writeToFile(Matrix A, String fileName) throws IOException {
		if (A == null || fileName == null)
			return;
		
		try (BufferedWriter writer = Files.newBufferedWriter(
			FileSystems.getDefault().getPath(fileName), StandardCharsets.UTF_8, StandardOpenOption.CREATE)) {
			
			int rows = A.rows();
			int columns = A.columns();
			for (int i = 0; i < rows; i++) {
				for (int j = 0; j < columns; j++) {
					writer.append(String.valueOf(A.get(i, j)));
					if (j < columns - 1)
						writer.write(" ");
				}
				if (i < rows - 1)
					writer.newLine();
			}
		}
	}
}